//
//  FormBaseView.swift
//  Pods
//
//  Created by Alean on 2023/5/9.
//

import UIKit

public protocol FormableRow: class {
    func updateWithRowFormer(_ rowFormer: RowFormer)
}

open class RowFormer {
    public enum InstantiateType {
        case Class
        case Nib(nibName: String)
        case NibTag(nibName: String, tag:Int)
        case NibBundle(nibName: String, bundle: Bundle)
        case NibBundleTag(nibName: String, bundle: Bundle, tag:Int)
    }
    public internal(set) final weak var former: Former?

    public final let cellType: UITableViewCell.Type
    private final let instantiateType: RowFormer.InstantiateType
    internal final var cellSetup: ((UITableViewCell) -> Void)?
    public final var rowHeight: CGFloat = 44
    internal final var dynamicRowHeight: ((UITableView, IndexPath) -> CGFloat)?
    @discardableResult
    public final func dynamicRowHeight(_ handler: @escaping ((UITableView, IndexPath) -> CGFloat)) -> Self {
        dynamicRowHeight = handler
        return self
    }

    internal init<T: UITableViewCell>(
        cellType: T.Type,
        instantiateType: RowFormer.InstantiateType,
        cellSetup: ((T) -> Void)? = nil) {
            self.cellType = cellType
            self.instantiateType = instantiateType
            self.cellSetup = { cellSetup?(($0 as! T)) }
            initialized()
    }

    open func initialized() {

    }
    public final var enabled = true { didSet { update() } }
    open func cellSelected(indexPath: IndexPath) {
        if enabled {
            onSelected?(self)
        }
    }

    internal final var onSelected: ((RowFormer) -> Void)?
    internal final var onUpdate: ((RowFormer) -> Void)?
    open func update() {
        onUpdate?(self)
        if let formableRow = cellInstance as? FormableRow {
            formableRow.updateWithRowFormer(self)
        }
    }
    private final var _cellInstance: UITableViewCell?
    internal final var cellInstance: UITableViewCell {
        if _cellInstance == nil {
            var cell: UITableViewCell?
            switch instantiateType {
            case .Class:
                cell = cellType.init(style: .default, reuseIdentifier: cellType.identifier)
            case .Nib(let nibName):
                cell = Bundle.main.loadNibNamed(nibName, owner: nil, options: nil)!.first as? UITableViewCell
                assert(cell != nil, "[Former] Failed to load cell from nib (\(nibName)).")
            case .NibTag(let nibName, let tag):
                let nibChildren = Bundle.main.loadNibNamed(nibName, owner: nil, options: nil)!
                cell = nibChildren.first {($0 as? UIView)?.tag == tag} as? UITableViewCell
                assert(cell != nil, "[Former] Failed to load cell from nib (nibName: \(nibName)), tag: (\(tag)).")
            case .NibBundle(let nibName, let bundle):
                cell = bundle.loadNibNamed(nibName, owner: nil, options: nil)!.first as? UITableViewCell
                assert(cell != nil, "[Former] Failed to load cell from nib (nibName: \(nibName), bundle: \(bundle)).")
            case .NibBundleTag(let nibName, let bundle, let tag):
                let nibChildren = bundle.loadNibNamed(nibName, owner: nil, options: nil)!
                cell = nibChildren.first {($0 as? UIView)?.tag == tag} as? UITableViewCell
                assert(cell != nil, "[Former] Failed to load cell from nib (nibName: \(nibName), bundle: \(bundle), tag: \(tag)).")
            }
            _cellInstance = cell
            cellSetup?(cell!)
        }
        return _cellInstance!
    }
}

public protocol Formable: SelectableForm, UpdatableForm, ConfigurableForm {}

public protocol SelectableForm: class {}
public extension SelectableForm where Self: RowFormer {
    @discardableResult
    func onSelected(_ handler: @escaping ((Self) -> Void)) -> Self {
        onSelected = {
            handler($0 as! Self)
        }
        return self
    }
}

public protocol UpdatableForm: class {}
public extension UpdatableForm where Self: RowFormer {
    @discardableResult
    func update(_ handler: ((Self) -> Void)) -> Self {
        handler(self)
        update()
        return self
    }
    
    @discardableResult
    func onUpdate(_ handler: @escaping ((Self) -> Void)) -> Self {
        onUpdate = {
            handler($0 as! Self)
        }
        return self
    }
}

public protocol ConfigurableForm: class {}
public extension ConfigurableForm where Self: RowFormer {
    @discardableResult
    func configure(handler: ((Self) -> Void)) -> Self {
        handler(self)
        return self
    }
}

public final class SectionFormer {
    
    // MARK: Public
    
    public init(rowFormer: RowFormer...) {
        self.rowFormers = rowFormer
    }
    
    public init(rowFormers: [RowFormer] = []) {
        self.rowFormers = rowFormers
    }
    
    /// All RowFormers. Default is empty.
    public private(set) var rowFormers = [RowFormer]()
    public var numberOfRows: Int {
        return rowFormers.count
    }
    public subscript(index: Int) -> RowFormer {
        return rowFormers[index]
    }
    @discardableResult
    public func append(rowFormer: RowFormer...) -> Self {
        add(rowFormers: rowFormer)
        return self
    }
    
    /// Add RowFormers to last index.
    @discardableResult
    public func add(rowFormers: [RowFormer]) -> Self {
        self.rowFormers += rowFormers
        return self
    }
    
    /// Insert RowFormer to any index.
    @discardableResult
    public func insert(rowFormer: RowFormer..., toIndex: Int) -> Self {
        let count = self.rowFormers.count
        if count == 0 ||  toIndex >= count {
            add(rowFormers: rowFormers)
            return self
        }
        self.rowFormers.insert(contentsOf: rowFormers, at: toIndex)
        return self
    }
    @discardableResult
    public func remove(rowFormer: RowFormer...) -> Self {
        var removedCount = 0
        for (index, rowFormer) in self.rowFormers.enumerated() {
            if rowFormers.contains(where: { $0 === rowFormer }) {
                remove(atIndex: index)
                removedCount += 1
                if removedCount >= rowFormers.count {
                    return self
                }
            }
        }
        return self
    }
    
    /// Remove RowFormers from instances of RowFormer.
    @discardableResult
    public func remove(rowFormers: [RowFormer]) -> Self {
        var removedCount = 0
        for (index, rowFormer) in self.rowFormers.enumerated() {
            if rowFormers.contains(where: { $0 === rowFormer }) {
                remove(atIndex: index)
                removedCount += 1
                if removedCount >= rowFormers.count {
                    return self
                }
            }
        }
        return self
    }
    
    /// Remove RowFormer from index.
    @discardableResult
    public func remove(atIndex: Int) -> Self {
        rowFormers.remove(at: atIndex)
        return self
    }
}

public final class Former: NSObject {
    fileprivate weak var tableView: UITableView?

    deinit {
        tableView?.delegate = nil
        tableView?.dataSource = nil
        NotificationCenter.default.removeObserver(self)
    }

    public init(tableView: UITableView) {
        super.init()
        self.tableView = tableView
        setupTableView()
    }

    private func setupTableView() {
        tableView?.delegate = self
        tableView?.dataSource = self
    }

    @discardableResult
    public func reload() -> Self {
        tableView?.reloadData()
        return self
    }

    @discardableResult
    public func endEditing() -> Self {
        tableView?.endEditing(true)
        return self
    }
    fileprivate var selectedIndexPath: IndexPath?
    @discardableResult
    public func deselect(animated: Bool) -> Self {
        if let indexPath = selectedIndexPath {
            tableView?.deselectRow(at: indexPath, animated: animated)
        }
        return self
    }

    fileprivate var onCellSelected: ((IndexPath) -> Void)?
    fileprivate var onScroll: ((UIScrollView) -> Void)?
    fileprivate var onBeginDragging: ((UIScrollView) -> Void)?
    fileprivate var willDeselectCell: ((IndexPath) -> IndexPath?)?
    fileprivate var willDisplayCell: ((IndexPath) -> Void)?
    fileprivate var willDisplayHeader: ((Int) -> Void)?
    fileprivate var willDisplayFooter: ((Int) -> Void)?
    fileprivate var didDeselectCell: ((IndexPath) -> Void)?

    public func rowFormer(indexPath: IndexPath) -> RowFormer {
        return self[indexPath.section][indexPath.row]
    }

    public private(set) var sectionFormers = [SectionFormer]()
    /// Return all RowFormers. Compute each time of called.
    public var rowFormers: [RowFormer] {
        return sectionFormers.flatMap { $0.rowFormers }
    }
    
    /// Number of all sections.
    public var numberOfSections: Int {
        return sectionFormers.count
    }
    
    /// Number of all rows.
    public var numberOfRows: Int {
        return rowFormers.count
    }

    @discardableResult
    public func append(sectionFormer: SectionFormer...) -> Self {
        return add(sectionFormers: sectionFormer)
    }
    @discardableResult
    public func add(sectionFormers: [SectionFormer]) -> Self {
        self.sectionFormers += sectionFormers
        return self
    }
    
    /// Insert SectionFormer to index of section with NO updates.
    @discardableResult
    public func insert(sectionFormer: SectionFormer..., toSection: Int) -> Self {
        return insert(sectionFormers: sectionFormer, toSection: toSection)
    }
    
    /// Insert SectionFormers to index of section with NO updates.
    @discardableResult
    public func insert(sectionFormers: [SectionFormer], toSection: Int) -> Self {
        let count = self.sectionFormers.count
        if count == 0 ||  toSection >= count {
            add(sectionFormers: sectionFormers)
            return self
        } else if toSection >= count {
            self.sectionFormers.insert(contentsOf: sectionFormers, at: 0)
            return self
        }
        self.sectionFormers.insert(contentsOf: sectionFormers, at: toSection)
        return self
    }
}
extension Former: UITableViewDelegate, UITableViewDataSource {
    public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        endEditing()
        onBeginDragging?(scrollView)
    }
    
    
    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        onScroll?(scrollView)
    }
    public func tableView(_ tableView: UITableView, willDeselectRowAt indexPath: IndexPath) -> IndexPath? {
        return willDeselectCell?(indexPath) ?? indexPath
    }
    
    public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        willDisplayCell?(indexPath)
    }
    public func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        endEditing()
        deselect(animated: false)
        selectedIndexPath = indexPath
        return indexPath
    }
    

    public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let rowFormer = self.rowFormer(indexPath: indexPath)
        rowFormer.cellSelected(indexPath: indexPath)
        onCellSelected?(indexPath)
    }
    
    public func numberOfSections(in tableView: UITableView) -> Int {
        return numberOfSections
    }

    public subscript(index: Int) -> SectionFormer {
        return sectionFormers[index]
    }

    public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self[section].numberOfRows
    }

    public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        let rowFormer = self.rowFormer(indexPath: indexPath)
        if let dynamicRowHeight = rowFormer.dynamicRowHeight {
            rowFormer.rowHeight = dynamicRowHeight(tableView, indexPath)
        }
        return rowFormer.rowHeight
    }

    public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        let rowFormer = self.rowFormer(indexPath: indexPath)
        if let dynamicRowHeight = rowFormer.dynamicRowHeight {
            rowFormer.rowHeight = dynamicRowHeight(tableView, indexPath)
        }
        return rowFormer.rowHeight
    }
    
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let rowFormer = self.rowFormer(indexPath: indexPath)
        if rowFormer.former == nil { rowFormer.former = self }
        rowFormer.update()
        return rowFormer.cellInstance
    }

}
open class BaseRowFormer<T: UITableViewCell>: RowFormer {
    public var cell: T {
        return cellInstance as! T
    }
    
    required public init(
        instantiateType: RowFormer.InstantiateType = .Class,
        cellSetup: ((T) -> Void)? = nil) {
        super.init(
            cellType: T.self,
            instantiateType: instantiateType,
            cellSetup: cellSetup
            )
    }
}

public protocol LabelFormableRow: FormableRow {
    func formTextLabel() -> UILabel?
    func formSubTextLabel() -> UILabel?
}

open class LabelRowFormer<T: UITableViewCell>: BaseRowFormer<T>, Formable where T: LabelFormableRow {
    open var text: String?
    open var subText: String?

    open override func update() {
        super.update()
        let textLabel = cell.formTextLabel()
        let subTextLabel = cell.formSubTextLabel()
        textLabel?.text = text
        subTextLabel?.text = subText
    }
}

public protocol TextFieldFormableRow: FormableRow {
    func formTextField() -> UITextField
    func formTitleLabel() -> UILabel?
}

open class TextFieldRowFormer<T: UITableViewCell>
: BaseRowFormer<T>, Formable where T: TextFieldFormableRow {
    private final var onTextChanged: ((String) -> Void)?
    open var text: String?
    open var placeholder: String?
    open var attributedPlaceholder: NSAttributedString?

    open override func update() {
        super.update()
        
        cell.selectionStyle = .none
        let titleLabel = cell.formTitleLabel()
        let textField = cell.formTextField()
        textField.text = text
        _ = placeholder.map { textField.placeholder = $0 }
        _ = attributedPlaceholder.map { textField.attributedPlaceholder = $0 }
    }
    @discardableResult
    public final func onTextChanged(_ handler: @escaping ((String) -> Void)) -> Self {
        onTextChanged = handler
        return self
    }

}

open class FormCell: UITableViewCell, FormableRow {
    // MARK: Public
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }
    override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setup()
    }
    
    open func updateWithRowFormer(_ rowFormer: RowFormer) {}
    
    open func setup() {
        contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        textLabel?.backgroundColor = .clear
    }
}

open class FormTextFieldCell: FormCell, TextFieldFormableRow {
    public private(set) weak var textField: UITextField!
    public private(set) weak var titleLabel: UILabel!

    public func formTextField() -> UITextField {
        return textField
    }
    
    public func formTitleLabel() -> UILabel? {
        return titleLabel
    }

    open override func setup() {
        
        super.setup()
        
        let titleLabel = UILabel()
        titleLabel.setContentHuggingPriority(UILayoutPriority(rawValue: 500), for: NSLayoutConstraint.Axis.horizontal)
        titleLabel.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 1000), for: .horizontal)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        contentView.insertSubview(titleLabel, at: 0)
        self.titleLabel = titleLabel
        
        let textField = UITextField()
        textField.backgroundColor = .clear
        textField.clearButtonMode = .whileEditing
        textField.translatesAutoresizingMaskIntoConstraints = false
        contentView.insertSubview(textField, at: 0)
        self.textField = textField
    }
}
final class CenterLabelCell: FormCell, LabelFormableRow {
    
    // MARK: Public
    
    func formTextLabel() -> UILabel? {
        return titleLabel
    }
    
    func formSubTextLabel() -> UILabel? {
        return nil
    }
    
    weak var titleLabel: UILabel!
    
    override func setup() {
        super.setup()
        
        let titleLabel = UILabel()
        titleLabel.textColor = .yellow
        titleLabel.font = .boldSystemFont(ofSize: 15)
        titleLabel.textAlignment = .center
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(titleLabel)
        self.titleLabel = titleLabel
    }
}

import SnapKit
open class FormBaseView: UIView  {

    public let tableView: UITableView = {
        let tableView = UITableView(frame: .zero, style: .plain)
        tableView.backgroundColor = .clear
        tableView.separatorStyle = .none
//        tableView.separatorStyle = .singleLine
//        tableView.separatorInset = UIEdgeInsets(top: 0, left: 13, bottom: 0, right: 13)
        tableView.estimatedRowHeight = 0
        tableView.rowHeight = UITableView.automaticDimension

        tableView.estimatedSectionHeaderHeight = 0
        tableView.sectionHeaderHeight = UITableView.automaticDimension

        tableView.estimatedSectionFooterHeight = 0
        tableView.sectionFooterHeight = UITableView.automaticDimension

        tableView.showsHorizontalScrollIndicator = false
        tableView.showsVerticalScrollIndicator = false
//        tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 67, right: 0)

        tableView.tableFooterView = UIView()
        if #available(iOS 15.0, *) {
            tableView.sectionHeaderTopPadding = 0
        } else {
            // Fallback on earlier versions
        }
        if #available(iOS 11.0, *) {
            tableView.contentInsetAdjustmentBehavior = .never
        } else {
            topViewController()?.automaticallyAdjustsScrollViewInsets = false
        }
        return tableView
    }()

    public override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    public convenience init() {
        self.init(frame: .zero)
    }
    
    public required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private lazy var former: Former = Former(tableView: self.tableView)

    private final func setup() {
        addSubview(tableView)
        tableView.snp.makeConstraints { make in
            make.left.right.top.bottom.equalToSuperview()
        }
        let idRow = TextFieldRowFormer<FormTextFieldCell>() {
            $0.textField.textColor = .yellow
            $0.textField.font = .systemFont(ofSize: 15)
        }.configure {
            $0.placeholder = "User name"
            $0.text = "Login.sharedInstance.username"
        }.onTextChanged {[weak self] _ in
            //                Login.sharedInstance.username = $0
            //                self?.switchLoginRow()
        }

//        LabelRowFormer<CenterLabelCell>.init(instantiateType: .Class) { cell in
//
//        }
        let loginRow = LabelRowFormer<CenterLabelCell>(){_ in
//            $0.titleLabel
        }
            .configure {
                $0.text = "Login"
                $0.rowHeight = UITableView.automaticDimension

            }.onSelected { [weak self] _ in
                //                self?.dismiss(animated: true, completion: nil)
            }

        let idSection = SectionFormer(rowFormer: idRow)
        let loginSection = SectionFormer(rowFormer: loginRow)
        former.append(sectionFormer: idSection, loginSection)
        former.reload()
    }
}
//open class FormBaseView: WDBaseCellView<MVVMBaseModelProtocol> {
//
//    /*
//    // Only override draw() if you perform custom drawing.
//    // An empty implementation adversely affects performance during animation.
//    override func draw(_ rect: CGRect) {
//        // Drawing code
//    }
//    */
//
//}
